package org.arl.modem.codec;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Random;

/*
 * class RsLtRlEncoder Description: Implements APIs for LT codes with Kent Maps
 */
public class LTKentMapEncoder extends Encoder {
   /**
    * 
    */
   private static final long serialVersionUID = 1L;

   // protected int seed;
   // protected boolean[] position;
   // protected byte[][] message;
   // protected int galoisField;
   // public int sizeOfPacket;
   // public int numOfMessages;
   // protected int numOfPackets;
   // protected int numOfSourceMessages;
   // protected float constantC;
   // protected float initVal;
   // protected float key;
   // protected int encodeMessageIndex;
   // private byte[] bytes;

   /*
    * Decription: Constructor for LT encoder using Kent map random number
    * generator Input arguments: : fieldSize : size of the Galois Field
    * (currently it supports only a field size of 2) pktSize : size of each
    * message symbol numOfPackets : number of packets that can be sent to the
    * channel (currently it stores values and does not queue packets) constantC:
    * This is the constant c in RS distribution, which is greater than 0.
    * initVal: Initial value to the chaotic Kent map random number generator
    * key: Key value to the Kent map random number generator. Equivalent to
    * seed. (Currently not used) Returns:None
    */
   public LTKentMapEncoder(int fieldSize, int pktSize, int numOfPackets,
         float constantC, float initVal, float key, byte[] b) {

      galoisField = fieldSize;
      sizeOfPacket = pktSize;
      packet = new byte[sizeOfPacket];
      this.numOfPackets = numOfPackets;

      this.constantC = constantC;
      this.initVal = initVal;
      this.key = key;
      encodeMessageIndex = 0;
      bytes = b;
   }

   /*
    * Description: Reads bytes from the input byte stream Input arguments: none
    * Returns: 1 on successful read
    */
   public int readMessage() {
      float numOfSourceMessages = 0;
      numOfMessages = bytes.length;
      numOfSourceMessages = (float) Math.ceil((float) numOfMessages
            / sizeOfPacket);
      System.out.println("Number of Source Messages generated"
            + numOfSourceMessages);

      this.numOfSourceMessages = (int) numOfSourceMessages;
      System.out.println("number of bytes in the file " + numOfMessages);

      message = new byte[this.numOfSourceMessages][sizeOfPacket];

      for (int i = 0; i < this.numOfSourceMessages; i++) {
         for (int k = 0; k < sizeOfPacket; k++) {
            if ((i * sizeOfPacket + k) < bytes.length)
               message[i][k] = bytes[i * sizeOfPacket + k];
         }
      }

      return numOfMessages;
   }

   public int getSeed() {
      return seed;
   }

   public void setSeed(int seed) {
      this.seed = seed;
   }

   /*
    * Description: Encodes message symbols to encoded symbols Input arguments:
    * none Returns : encoded packet
    */
   public CodecPacket encodeMessage() {
      int randomNumber = 0;
      degree = 0;
      int index = 0;
      byte[] temp = new byte[sizeOfPacket];
      int index2 = 0;
      KentMap kentMap1 = new KentMap();
      float rando = 0;
      if (encodeMessageIndex >= numOfSourceMessages) {
         encodeMessageIndex = 0;
      }
      Random randGen1 = new Random();
      while (true) {
         rando = (kentMap1.kentMap(numOfSourceMessages,
               (float) randGen1.nextDouble(), encodeMessageIndex,
               (float) randGen1.nextDouble()));
         RevisedRobustSoliton obj = new RevisedRobustSoliton();
         degree = obj.randomnumgen(numOfSourceMessages, (float) constantC,
               (float) rando, (float) 0.01);
         if (degree < numOfSourceMessages) {
            break;
         }
         encodeMessageIndex++;
         if (encodeMessageIndex >= numOfSourceMessages) {
            encodeMessageIndex = 0;
         }
      }
      KentMap kentMap2 = new KentMap();
      Random randGen = new Random(encodeMessageIndex);
      kentMap2.kentMap(numOfSourceMessages, (float) (randGen.nextDouble()), 1,
            (float) (randGen.nextDouble()));
      for (index = 0; index < degree; index++) {
         randomNumber = kentMap2.kentMap1(numOfSourceMessages);
         for (index2 = 0; index2 < sizeOfPacket; index2++) {
            temp[index2] = (byte) (temp[index2] ^ message[randomNumber][index2]);
         }

      }

      for (index2 = 0; index2 < sizeOfPacket; index2++) {
         packet[index2] = temp[index2];

      }
      seed = encodeMessageIndex;
      encodeMessageIndex++;
      CodecPacket cp = new CodecPacket(packet, seed, degree);
      return cp;

   }

   /*
    * Description: writes encoded symbol to the channel stream Input arguments:
    * packet - encoded packet Returns: None
    */
   public void writePacket(byte[] packet) {

      FileOutputStream outFile = null;
      ObjectOutputStream out = null;
      int index = 0;
      try {
         outFile = new FileOutputStream("channel.dat");
         out = new ObjectOutputStream(outFile);
         CodecPacket obj = new CodecPacket();
         obj.header = seed;
         obj.packet = new byte[sizeOfPacket];
         for (index = 0; index < sizeOfPacket; index++) {

            obj.packet[index] = packet[index];
         }
         obj.degree = degree;

         out.writeObject(obj);
      } catch (IOException ioe) {
      } finally {
         if (out != null) {
            try {
               out.close();
            } catch (IOException ioe) {
            }
         }
      }
   }

   @Override
   public boolean packetAvailable() {
      return false;
   }

   @Override
   public void readPacket() {

   }

   @Override
   public int getCodedPacketSize() {
      return -1;
   }

   @Override
   public void decodeMessage(CodecPacket pkt) {

   }

   @Override
   public int numPacketsReceived() {
      return 0;
   }

   @Override
   public void writeMessage() {
      throw new UnsupportedOperationException("Not supported yet.");
   }
}
